﻿using System;
using System.Data;
using System.Reflection;
using System.Reflection.Emit;

namespace Xin478.CSWork.Common
{

    //public class DynamicBuilder<T>
    //{
    //    private static readonly MethodInfo getValueMethod =
    //        typeof(IDataRecord).GetMethod("get_Item", new Type[] { typeof(int) });
    //    private static readonly MethodInfo isDBNullMethod =
    //        typeof(IDataRecord).GetMethod("IsDBNull", new Type[] { typeof(int) });
    //    private delegate T Load(IDataRecord dataRecord);
    //    private Load handler;

    //    private DynamicBuilder() { }

    //    public T Build(IDataRecord dataRecord)
    //    {
    //        return handler(dataRecord);
    //    }

    //    public static DynamicBuilder<T> CreateBuilder(IDataRecord dataRecord)
    //    {
    //        DynamicBuilder<T> dynamicBuilder = new DynamicBuilder<T>();

    //        DynamicMethod method = new DynamicMethod("DynamicCreate", typeof(T),
    //                new Type[] { typeof(IDataRecord) }, typeof(T), true);
    //        ILGenerator generator = method.GetILGenerator();

    //        LocalBuilder result = generator.DeclareLocal(typeof(T));
    //        generator.Emit(OpCodes.Newobj, typeof(T).GetConstructor(Type.EmptyTypes));
    //        generator.Emit(OpCodes.Stloc, result);

    //        for (int i = 0; i < dataRecord.FieldCount; i++)
    //        {
    //            PropertyInfo propertyInfo = typeof(T).GetProperty(dataRecord.GetName(i));
    //            Label endIfLabel = generator.DefineLabel();

    //            if (propertyInfo != null && propertyInfo.GetSetMethod() != null)
    //            {
    //                generator.Emit(OpCodes.Ldarg_0);
    //                generator.Emit(OpCodes.Ldc_I4, i);
    //                generator.Emit(OpCodes.Callvirt, isDBNullMethod);
    //                generator.Emit(OpCodes.Brtrue, endIfLabel);

    //                generator.Emit(OpCodes.Ldloc, result);
    //                generator.Emit(OpCodes.Ldarg_0);
    //                generator.Emit(OpCodes.Ldc_I4, i);
    //                generator.Emit(OpCodes.Callvirt, getValueMethod);
    //                generator.Emit(OpCodes.Unbox_Any, dataRecord.GetFieldType(i));
    //                generator.Emit(OpCodes.Callvirt, propertyInfo.GetSetMethod());

    //                generator.MarkLabel(endIfLabel);
    //            }
    //        }

    //        generator.Emit(OpCodes.Ldloc, result);
    //        generator.Emit(OpCodes.Ret);

    //        dynamicBuilder.handler = (Load)method.CreateDelegate(typeof(Load));
    //        return dynamicBuilder;
    //    }
    //}

    public class EntityBuilder<Entity>
    {
        private delegate Entity Load(IDataReader dataReader);
        private Load handler;

        private EntityBuilder() { }

        public Entity Build(IDataReader reader)
        {
            //MethodInfo _me = handler.Method;
            //_me.ToString();
            return handler(reader);
        }

        public static EntityBuilder<Entity> CreateBuilder(IDataRecord reader)
        {
            EntityBuilder<Entity> result = new EntityBuilder<Entity>();
            DynamicMethod method = new DynamicMethod("CreateBuilder", typeof(Entity), new Type[] { typeof(IDataReader) }, typeof(Entity), true);
            ILGenerator generator = method.GetILGenerator();
            generator.DeclareLocal(typeof(Entity));
            generator.Emit(OpCodes.Newobj, typeof(Entity).GetConstructor(Type.EmptyTypes));
            generator.Emit(OpCodes.Stloc_0);
            MethodInfo getValue = reader.GetType().GetMethod("get_Item", new Type[] { typeof(int) });
            for (int i = 0; i < reader.FieldCount; i++)
            {

                PropertyInfo propertyInfo = typeof(Entity).GetProperty(reader.GetName(i));
                if (propertyInfo != null && propertyInfo.GetSetMethod() != null)
                {
                    Label label = generator.DefineLabel();
                    generator.Emit(OpCodes.Ldarg_0);
                    generator.Emit(OpCodes.Ldc_I4, i);
                    generator.Emit(OpCodes.Callvirt, reader.GetType().GetMethod("IsDBNull"));
                    generator.Emit(OpCodes.Brtrue, label);
                    generator.Emit(OpCodes.Ldloc_0);
                    generator.Emit(OpCodes.Ldarg_0);
                    generator.Emit(OpCodes.Ldc_I4, i);
                    generator.Emit(OpCodes.Callvirt, getValue);
                    generator.Emit(OpCodes.Unbox_Any, reader.GetFieldType(i));
                    generator.Emit(OpCodes.Callvirt, propertyInfo.GetSetMethod());
                    generator.MarkLabel(label);
                }
            }
            generator.Emit(OpCodes.Ldloc_0);
            generator.Emit(OpCodes.Ret);
            result.handler = (Load)method.CreateDelegate(typeof(Load));
            return result;
        }
    }
}
